/* 
 * This is a WIN32 Select module for the poor Windows User.
 * Turn to use linux please if you want to ***BURST*** the speed !!!
 */

#include <burst_kernel.h>
#define BUS_SELECT_ARRAY_ITEM 65536

static fd_set FdRead;
static fd_set FdWrite;
static bus_event_t *EventArray[BUS_SELECT_ARRAY_ITEM];

extern bus_module_t bus_select_module;

static void bus_win32_select_add(void *rsv, bus_event_t *ev)
{
	FD_SET(ev->sockfd, &FdRead);
	FD_SET(ev->sockfd, &FdWrite);
	EventArray[ev->sockfd] = ev;
}

static void bus_win32_select_del(void *rsv, bus_event_t *ev)
{
	FD_CLR(ev->sockfd, &FdRead);
	FD_CLR(ev->sockfd, &FdWrite);
	EventArray[ev->sockfd] = 0;
}

static struct list_head *bus_win32_select_process(void *rsv)
{
	int i;
	int err;
	struct list_head *first = 0;
	fd_set tmp_fdread = FdRead;
	fd_set tmp_fdwrite = FdWrite;
retry:
	err = select(0, &tmp_fdread, &tmp_fdwrite, 0, 0);
	if(err == SOCKET_ERROR) {
		for(i = 0;i < FdRead.fd_count;i++) {
			int n;
			int s = sizeof(int);
			err = getsockopt(FdRead.fd_array[i], SOL_SOCKET, SO_TYPE, (char *)&n, &s);
			if(err == -1) {
				bus_debug_print(BUS_ERROR "Set : #%d Val: %d : Invalid.\n", i, FdRead.fd_array[i]);
				FD_CLR(FdRead.fd_array[i], &FdRead);
			}else {
				bus_debug_print(BUS_ERROR "Set : #%d Val: %d : Ok.\n", i, FdRead.fd_array[i]);
			}
		}
		for(i = 0;i < FdWrite.fd_count;i++) {
			int n;
			int s = sizeof(int);
			err = getsockopt(FdWrite.fd_array[i], SOL_SOCKET, SO_TYPE, (char *)&n, &s);
			if(err == -1) {
				bus_debug_print(BUS_ERROR "Set : #%d Val: %d : Invalid.\n", i, FdWrite.fd_array[i]);
				FD_CLR(FdWrite.fd_array[i], &FdWrite);
			}else {
				bus_debug_print(BUS_MESSAGE "Set : #%d Val: %d : Ok.\n", i, FdWrite.fd_array[i]);
			}
		}
		if(!FdRead.fd_count && !FdWrite.fd_count) {
			bus_panic("bus_win32_select_process", "win32-event-select-module.c", 256, 50000, "No any module.");
		}
		goto retry;
	}
	for(i = 0;i < tmp_fdread.fd_count;i++) {
		if(!first) {
			INIT_LIST_HEAD(&EventArray[tmp_fdread.fd_array[i]]->list);
			first = &EventArray[tmp_fdread.fd_array[i]]->list;
		}else {
			list_add_tail(&EventArray[tmp_fdread.fd_array[i]]->list, first);
		}
		bus_event_set(EventArray[tmp_fdread.fd_array[i]], BUS_IO_READING);
	}
	for(i = 0;i < tmp_fdwrite.fd_count;i++) {
		if(!first) {
			INIT_LIST_HEAD(&EventArray[tmp_fdwrite.fd_array[i]]->list);
			first = &EventArray[tmp_fdwrite.fd_array[i]]->list;
		}else {
			list_add_tail(&EventArray[tmp_fdwrite.fd_array[i]]->list, first);
		}
		bus_event_set(EventArray[tmp_fdread.fd_array[i]], BUS_IO_WRITING);
	}
	return first;
}

static bus_module_t *bus_dummy_init(bus_kernel_t *dummy)
{
	return &bus_select_module;
}

static bus_module_desc_t bus_win32_select_module_info = {
	BUS_MODULE_EVENT,
	"Brain Fuck Event Reactor", 
	"Human face", 
	"This is a brain-damaged inline event module", 
	"0.0.0.1"
};

bus_event_module_t bus_win32_select_module = {
	&bus_win32_select_add, 
	&bus_win32_select_del, 
	&bus_win32_select_process, 
};

bus_module_t bus_select_module = { 
	&bus_win32_select_module_info,
	&bus_dummy_init, 
	0, 
	0, 
	&bus_win32_select_module
};
